package com.ccx.demo.business.common.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ccx.demo.business.common.service.IFileService;
import com.ccx.demo.business.common.vo.FileInfo;
import com.ccx.demo.business.common.vo.UserFileInfo;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.support.annotations.AppSwaggerGroup;
import com.support.annotations.VueSwaggerGroup;
import com.support.annotations.WechatSwaggerGroup;
import com.support.mvc.entity.base.Item;
import com.support.mvc.entity.base.Result;
import com.utils.enums.Code;
import com.utils.util.FPath;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;

@Api(tags = "文件上传")
@ApiSort(5)
@Controller
@RequestMapping("/upload")
@Slf4j
@RequiredArgsConstructor
public class UploadController {
    private final IFileService fileService;

    @ApiOperation(value = "", hidden = true)
    @PostMapping("/test")
    @ResponseBody
    public Result<Void> test(@RequestParam(required = false) final MultipartFile file) {
        return new Result<Void>().call(() -> {
            try {
                log.info("{}", JSON.toJSONString(fileService.write(
                        file,
                        FileInfo.valueOf(FPath.FileName
                                .of(file.getOriginalFilename(), "level-1", "level-2")
                                .buildMd5Uname(file.getInputStream())
                        )
                )));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            String content = "文本内容";
            log.info("{}", JSON.toJSONString(fileService.write(
                    content,
                    FileInfo.valueOf(FPath.FileName
                            .of("text.txt")
                            .buildMd5Uname(content)
                    )
            )));
            byte[] bytes = "二进制内容".getBytes(UTF_8);
            log.info("{}", JSON.toJSONString(fileService.write(
                    bytes,
                    FileInfo.valueOf(FPath.FileName
                            .of("bytes.txt")
                            .buildMd5Uname(bytes)
                    )
            )));
            File file1 = new File("/home/ccx/git-repository/common-mvc-parent/doc/nginx.conf");
            log.info("{}", JSON.toJSONString(fileService.write(
                    file1,
                    FileInfo.valueOf(FPath.FileName
                            .of("nginx.conf", "level-1", "config")
                            .buildMd5Uname(file1)
                    )
            )));
            final FileInfo resultFileInfo = fileService.writeJson(
                    new Result<Item>()
                            .setSuccess(Item.builder()
                                    .key("item key")
                                    .value("1")
                                    .comment("说明")
                                    .build()
                            ),
                    FileInfo.valueOf(FPath.FileName.of("result.json"))
            );
            log.info("{}", JSON.toJSONString(resultFileInfo));
            log.info("{}", fileService
                    .readJson(
                            resultFileInfo,
                            new TypeReference<Result<Item>>() {
                            }
                    )
                    .map(JSON::toJSONString)
                    .orElse("文件不存在")
            );

            try {
                Files.list(Paths.get("/home/ccx/git-repository/common-mvc-parent/logs"))
                        .filter(path -> !Objects.equals("app-demo.log", path.toFile().getName()))
                        .forEach(path -> {
                            log.info("{}", JSON.toJSONString(fileService.write(
                                    path.toFile(),
                                    FileInfo.valueOf(FPath.FileName
                                            .of(path.toFile().getName(), "logs")
                                            .buildMd5Uname(path.toFile())
                                    )
                            )));
                        });
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        });
    }

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @ApiOperation(value = "1.上传到临时目录，单个上传")
    @ApiOperationSupport(order = 1, author = "谢长春")
    @PostMapping("/temp")
    @ResponseBody
    public Result<FileInfo> uploadFileTemp(@RequestParam(required = false) final MultipartFile file) {
        return new Result<FileInfo>().execute(result -> {
            if (Objects.isNull(file) || StringUtils.isBlank(file.getOriginalFilename())) {
                throw Code.A00009.toCodeException("上传文件为空,字段【file】只能是单个文件");
            }
            Code.A00001.assertNonBlank(file.getOriginalFilename(), "参数【originalFilename】不能为空");
            try {
                result.setSuccess(fileService.write(
                                file,
                                FileInfo.valueOf(FPath.FileName
                                        .of(file.getOriginalFilename())
                                        .buildMd5Uname(file.getInputStream())
                                )
                        )
                );
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @ApiOperation(value = "2.上传到临时目录，批量上传")
    @ApiOperationSupport(order = 2, author = "谢长春")
    @PostMapping("/temps")
    @ResponseBody
    public Result<FileInfo> uploadFilesTemp(@RequestParam(required = false) final MultipartFile[] files) {
        return new Result<FileInfo>().execute(result -> {
            if (Objects.isNull(files) || StringUtils.isBlank(files[0].getOriginalFilename())) {
                throw Code.A00009.toCodeException("上传文件为空,字段【files】为数组");
            }
            result.setSuccess(Stream.of(files)
                    .map(file -> {
                                Code.A00001.assertNonBlank(file.getOriginalFilename(), "参数【originalFilename】不能为空");
                                try {
                                    return fileService.write(
                                            file,
                                            FileInfo.valueOf(FPath.FileName
                                                    .of(file.getOriginalFilename())
                                                    .buildMd5Uname(file.getInputStream())
                                            )
                                    );
                                } catch (IOException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                    )
                    .collect(Collectors.toList())
            );
        });
    }

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @ApiOperation(value = "3.上传到用户目录，单个上传：用户头像")
    @ApiOperationSupport(order = 3, author = "谢长春")
    @PostMapping("/user")
    @ResponseBody
    public Result<UserFileInfo> uploadFileUser(@RequestParam(required = false) final MultipartFile file) {
        return new Result<UserFileInfo>().execute(result -> {
            if (Objects.isNull(file) || StringUtils.isBlank(file.getOriginalFilename())) {
                throw Code.A00009.toCodeException("上传文件为空,字段【file】只能是单个文件");
            }
            Code.A00001.assertNonBlank(file.getOriginalFilename(), "参数【originalFilename】不能为空");
            try {
                result.setSuccess(fileService.write(
                                file,
                                UserFileInfo.valueOf(FPath.FileName
                                        .of(file.getOriginalFilename())
                                        .buildMd5Uname(file.getInputStream())
                                )
                        )
                );
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @ApiOperation(value = "4.上传到用户目录，批量上传：用户头像")
    @ApiOperationSupport(order = 4, author = "谢长春")
    @PostMapping("/users")
    @ResponseBody
    public Result<UserFileInfo> uploadFilesUser(@RequestParam(required = false) final MultipartFile[] files) {
        return new Result<UserFileInfo>().execute(result -> {
            if (Objects.isNull(files) || StringUtils.isBlank(files[0].getOriginalFilename())) {
                throw Code.A00009.toCodeException("上传文件为空,字段【files】为数组");
            }
            result.setSuccess(Stream.of(files)
                    .map(file -> {
                                Code.A00001.assertNonBlank(file.getOriginalFilename(), "参数【originalFilename】不能为空");
                                try {
                                    return fileService.write(
                                            file,
                                            UserFileInfo.valueOf(FPath.FileName
                                                    .of(file.getOriginalFilename())
                                                    .buildMd5Uname(file.getInputStream())
                                            )
                                    );
                                } catch (IOException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                    )
                    .collect(Collectors.toList())
            );
        });
    }
}
